package cEvent

import (
	"fmt"
	"reflect"

	"github.com/gin-gonic/gin"

	"gitee.com/csingo/cLog"

	"gitee.com/csingo/cEvent/interfaces"
)

func handle(instance interfaces.EventInterface) interfaces.EventHandler {
	app, name := instance.EventName()
	v := reflect.ValueOf(instance)
	method := v.MethodByName(event_handler_function_name)

	return func(ctx *gin.Context, data any) (err error) {
		defer func() {
			if r := recover(); r != nil {
				cLog.WithContext(ctx, map[string]any{
					"source": "cEvent.handle",
					"app":    app,
					"name":   name,
					"err":    r,
				}).Error("事件订阅异常退出")
			}
		}()

		results := method.Call([]reflect.Value{reflect.ValueOf(ctx), reflect.ValueOf(data)})
		result := results[0].Interface()
		if result == nil {
			return nil
		}
		return result.(error)
	}
}

func run() {
	container.Range(func(instance any) {
		e := instance.(interfaces.EventInterface)
		app, name := e.EventName()
		index := fmt.Sprintf(event_name_format, app, name)
		driver := container.GetDriver(index)
		if driver == nil {
			return
		}
		driver.LoadDriver(interfaces.Event{
			App:     app,
			Name:    name,
			Type:    reflect.TypeOf(e),
			Handler: handle(e),
		})
	})

	for _, event := range event_config.Events {
		index := fmt.Sprintf(event_name_format, event.App, event.Name)

		driver := container.GetDriver(index)
		if driver == nil {
			continue
		}
		driver.Subscribe()
	}
}

func Publish(ctx *gin.Context, data interfaces.EventInterface) {
	app, name := data.EventName()
	index := fmt.Sprintf(event_name_format, app, name)

	defer func() {
		if r := recover(); r != nil {
			cLog.WithContext(ctx, map[string]any{
				"source": "cEvent.Push",
				"app":    app,
				"name":   name,
				"err":    r,
			}).Error("事件推送失败")
		}
	}()

	driver := container.GetDriver(index)
	if driver == nil {
		return
	}
	driver.Publish(ctx, data)
}
